var NOT_MOVING = 0;
var MOVING_DRIVE = 1; // forward and backward
var MOVING_TURN = 2; // turning left and right

var mars = {send: function(){}}; // this will become the connection

function handler_text(params) {
    var code = params[0];
    var text = params[1];
    var msgclass;
    switch (code) {
        case 'connected':
            msgclass = 'good';
            break;
        case 'connection lost':
        case 'protocol error':
            msgclass = 'bad';
            break;
        case 'connection failed':
            msgclass = 'note';
            break;
        case 'chosen':
            msgclass = 'info';
            break;
        case 'not chosen':
            msgclass = 'info';
            break;
        case 'admin ok':
            msgclass = 'good';
            enable_admin_controls();
            break;
    }
    add_log(text, msgclass);
}

function enable_admin_controls() {
    var controls = document.getElementById('admin_controls');
    controls.style.display = 'block';
}

function handler_mars(params) {
    var code = params[0];
    var value = params[1];
    switch (code) {
        case 'R': // spectrum r
            add_log(code+':'+value, 'info');
            if (!calibrating) break;
            new_spectrum[2] += (1*value);
            break;
        case 'G': // spectrum g
            add_log(code+':'+value, 'info');
            if (!calibrating) break;
            new_spectrum[1] += (1*value);
            break;
        case 'B': // spectrum b
            add_log(code+':'+value, 'info');
            if (!calibrating) break;
            new_spectrum[0] += (1*value);
            spectrum_left++;
            break;
        case 'IR': // spectrum ir
            add_log(code+':'+value, 'info');
            if (!calibrating) break;
            new_spectrum[3] += (1*value);
            spectrum_left--;
            if (spectrum_left == 0) calibrate_done();
            break;
        case 'AX': // accelerometer x
        case 'AY': // accelerometer y
        case 'AZ': // accelerometer z
        case 'MX': // magnetic x
        case 'MY': // magnetic y
        case 'MZ': // magnetic z
        case 'AU': // solar panel
            break;
        case 'HU': // humidity
        case 'TE': // temperature
        case 'H': // camera horizontal
        case 'P': // camera vertical
            add_log(code+':'+value, 'info');
            break;
        default:
            add_log('Unknown message: "'+code+':'+value+'"', 'note');
            break;
    }
}

var current_controller = null;

function handler_server(params) {
    var code = params[0];
    var value = params[1];
    switch (code) {
        case 'current': // current controller
            if (value)
                current_controller = value;
            else
                current_controller = null;
            break;
        case 'client': // list a client
            var client = add_client(value, params[2], params[3], 'client');
            if (current_controller == value)
                client.className = 'client controller';
            break;
        case 'admin': // list an admin
            var client = add_client(value, params[2], params[3], 'admin');
            if (current_controller == value)
                client.className = 'admin controller';
            break;
        case 'spectrometer_calibration': // calibration data
            calibrate_got_old_data(value);
            break;
        case 'ping':
            mars.send('pong:'+value);
            break;
        case 'wheels_calibration': // set the wheels
            add_log('Setting wheel values '+value, 'info');
            wheels_data = value.split(',');
            mars.send('send:a'+wheels_data[0]);
            mars.send('send:b'+wheels_data[1]);
            mars.send('send:c'+wheels_data[2]);
            mars.send('send:d'+wheels_data[3]);
            mars.send('send:A'+wheels_data[4]);
            mars.send('send:B'+wheels_data[5]);
            mars.send('send:C'+wheels_data[6]);
            mars.send('send:D'+wheels_data[7]);
            mars.send('send:s');
            break;
    }
}

function add_log(text, msgclass) {
    function pad(num) {
        if (num < 10) return '0'+num;
        return ''+num;
    }
    var now = new Date();
    var h = now.getHours(), m = now.getMinutes(), s = now.getSeconds();
    var logtext = '['+pad(h)+':'+pad(m)+':'+pad(s)+'] '+text;
    var loglist = document.getElementById('loglist');
    var listnode = document.createElement('li');
    listnode.innerText = logtext;
    listnode.className = msgclass;
    loglist.appendChild(listnode);
    loglist.parentNode.scrollByLines(1);
}

function add_client(id, days, seconds, msgclass) {
    var clients = document.getElementById('clientlist');
    var listnode = document.createElement('li');
    listnode.innerText = id+'('+days+'d, '+seconds+'s)';
    listnode.className = msgclass;
    clients.appendChild(listnode);
    listnode.addEventListener('click', function (ev) {
        set_controller(id);
    }, false);
    return listnode;
}

function set_controller(id) {
    mars.send('ac:set control:'+id);
    refresh_clients();
}

function refresh_clients() {
    var clients = document.getElementById('clientlist');
    current_controller = null;
    while (clients.firstChild) {
        clients.removeChild(clients.firstChild);
    }
    mars.send('ac:get clients');
}

function setLanguage(langid) {
    mars.send('set:language:'+langid);
}

function make_connection() {
    function onopen(ev) {
        add_log('Connection established.', 'good');
        setLanguage('en');
        ask_password();
    }
    function onclose(ev) {
        add_log('Connection closed.', 'bad');
    }
    function onerror(ev) {
        add_log('Error happened in connection.', 'bad');
        mars.close();
    }
    mars = connect_to_mars('ws://'+document.location.hostname+':'+
        document.location.port+'/mars',
        onopen, onclose, onerror);
    mars.register_handler('TEXT', handler_text);
    mars.register_handler('mars', handler_mars);
    mars.register_handler('server', handler_server);
}

function ask_password() {
    var cmdline = document.getElementById('commandline');
    add_log('Give admin password below:', 'info');
    cmdline.value = '';
    cmdline.type = 'password';
    cmdline_handler = cmdline_password_handler;
    cmdline.focus();
}

var wheel_values = [0, 0, 0, 0, 0, 0, 0, 0]; // a,b,c,d,A,B,C,D
function save_wheel_data () {
    mars.send('set:wheels_calibration:'+wheel_values.join(','));
    mars.send('send:W');
}
function load_wheel_data () {
    mars.send('get:wheels_calibration');
}

function cmdline_command_handler (cmdline) {
    var value = cmdline.value;
    if (value.indexOf(':') == -1) {
        switch (value.charAt(0)) {
            case 'a':
                wheel_values[0] = value.substring(1);
                break;
            case 'b':
                wheel_values[1] = value.substring(1);
                break;
            case 'c':
                wheel_values[2] = value.substring(1);
                break;
            case 'd':
                wheel_values[3] = value.substring(1);
                break;
            case 'A':
                wheel_values[4] = value.substring(1);
                break;
            case 'B':
                wheel_values[5] = value.substring(1);
                break;
            case 'C':
                wheel_values[6] = value.substring(1);
                break;
            case 'D':
                wheel_values[7] = value.substring(1);
                break;
        }
        value = 'send:'+value;
    }
    mars.send(value);
    add_log(value, 'send');
    cmdline.value = '';
}

function cmdline_password_handler (cmdline) {
    mars.send('admin:'+cmdline.value);
    add_log('Password sent', 'info');
    cmdline.value = '';
    cmdline.type = 'text';
    cmdline_handler = cmdline_command_handler;
}

var cmdline_handler = cmdline_command_handler;

function calibrate_start () {
    // start calibration of the spectrometer
    // steps:
    // 1. request old calibration data
    // 2. measure spectrum
    // 3. display old data, new data and difference
    // 4. ask whether to save new data
    calibrating = true;
    add_log('Executing spectrometer calibration routine', 'info');
    mars.send('get:spectrometer_calibration');
    // reply is server:spectrometer_calibration:olddata
}

var calibrating = false;
var old_spectrum;
var new_spectrum;
var spectrum_left;
function calibrate_got_old_data (data) {
    add_log('Got old data', 'info');
    // Step 1 done, old data received
    if (data) {
        add_log('Data is "'+data+'" not empty', 'info');
        old_spectrum = data.split(',');
    }
    else {
        add_log('Old data is empty', 'info');
        old_spectrum = [0, 0, 0, 0];
    }
    // execute step 2, measure spectrum
    new_spectrum = [0, 0, 0, 0];
    spectrum_left = 0;
    add_log('Measuring new data', 'info');
    mars.send('send:m');
    // reply is bunch of B, G, R, and IR values
}

function calibrate_done () {
    // Step 2 done, new data received
    // Step 3: display new data and difference
    calibrating = false;
    var mean_spectrum = [
        new_spectrum[0]/5,
        new_spectrum[1]/5,
        new_spectrum[2]/5,
        new_spectrum[3]/5
    ];
    var diff_spectrum = [
        mean_spectrum[0] - old_spectrum[0],
        mean_spectrum[1] - old_spectrum[1],
        mean_spectrum[2] - old_spectrum[2],
        mean_spectrum[3] - old_spectrum[3]
    ];
    add_log('Old data: '+old_spectrum.join(','), 'info');
    add_log('New data: '+mean_spectrum.join(','), 'info');
    add_log('Difference: '+diff_spectrum.join(','), 'info');
    if (confirm('Do you want to save new calibration data?')) {
        calibrate_save(mean_spectrum.join(','));
    }
}

function calibrate_save (newdata) {
    // save new calibration data
    mars.send('set:spectrometer_calibration:'+newdata);
}

function initialize(ev) {
    // Initialization routines
    var cmdline = document.getElementById('commandline');
    cmdline.addEventListener('keypress', function (ev) {
        if (!cmdline.value) return;
        if (ev.keyCode == 13) cmdline_handler(cmdline);
    }, false);
    document.getElementById('halt').addEventListener('click',
        function (ev) {
            mars.send('ac:halt');
        }, false);
    document.getElementById('unhalt').addEventListener('click',
        function (ev) {
            mars.send('ac:unhalt');
        }, false);
    document.getElementById('refresh').addEventListener('click',
        function (ev) {
            refresh_clients();
        }, false);
    document.getElementById('calibrate').addEventListener('click',
        function (ev) {
            calibrate_start();
        }, false);
    document.getElementById('savewheels').addEventListener('click',
        function (ev) {
            save_wheel_data();
        }, false);
    document.getElementById('loadwheels').addEventListener('click',
        function (ev) {
            load_wheel_data();
        }, false);
    document.getElementById('reconnect').addEventListener('click',
        function (ev) {
            mars.send('ac:reconnect');
        }, false);
    make_connection(); // Make connection with the server
}

document.addEventListener('DOMContentLoaded', initialize, false);

